// Stanford Parser -- a probabilistic lexicalized NL CFG parser
// Copyright (c) 2002 - 2011 The Board of Trustees of
// The Leland Stanford Junior University. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// For more information, bug reports, fixes, contact:
//    Christopher Manning
//    Dept of Computer Science, Gates 1A
//    Stanford CA 94305-9010
//    USA
//    parser-support@lists.stanford.edu
//    http://nlp.stanford.edu/software/lex-parser.shtml

package edu.stanford.nlp.parser.lexparser;

import edu.stanford.nlp.io.IOUtils;
import edu.stanford.nlp.io.NumberRangeFileFilter;
import edu.stanford.nlp.io.NumberRangesFileFilter;
import edu.stanford.nlp.io.RuntimeIOException;
import edu.stanford.nlp.ling.HasWord;
import edu.stanford.nlp.objectbank.TokenizerFactory;
import edu.stanford.nlp.process.PTBTokenizer;
import edu.stanford.nlp.process.Tokenizer;
import edu.stanford.nlp.util.Function;
import edu.stanford.nlp.util.HashIndex;
import edu.stanford.nlp.util.Index;
import edu.stanford.nlp.trees.*;
import edu.stanford.nlp.trees.international.arabic.ArabicTreebankLanguagePack;
import edu.stanford.nlp.util.Pair;
import edu.stanford.nlp.util.Timing;
import edu.stanford.nlp.util.Triple;

import java.io.*;
import java.util.*;
import java.util.zip.GZIPOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

// Miscellaneous documentation by Roger (please correct any errors in this documentation!)
//
// I believe that a lexicalized parser is always constructed by creating a ParserData object and then calling
// makeParsers().
//

/**
 * This class provides the top-level API and command-line interface to a set
 * of reasonably good treebank-trained parsers.  The name reflects the main
 * factored parsing model, which provides a lexicalized PCFG parser
 * implemented as a product
 * model of a plain PCFG parser and a lexicalized dependency parser.
 * But you can also run either component parser alone.  In particular, it
 * is often useful to do unlexicalized PCFG parsing by using just that
 * component parser.
 * <p>
 * See the package documentation for more details and examples of use.
 * See the main method documentation for details of invoking the parser.
 * <p>
 * Note that training on a 1 million word treebank requires a fair amount of
 * memory to run.  Try -mx1500m.
 *
 * @author Dan Klein (original version)
 * @author Christopher Manning (better features, ParserParams, serialization)
 * @author Roger Levy (internationalization)
 * @author Teg Grenager (grammar compaction, tokenization, etc.)
 * @author Galen Andrew (considerable refactoring)
 */
public class CLexicalizedParser extends LexicalizedParser {

	public CLexicalizedParser() {
		super();
	}

	public CLexicalizedParser(ObjectInputStream in) throws Exception {
		super(in);
	}

	public CLexicalizedParser(Options op, String[] extraFlags) {
		super(op, extraFlags);
	}

	public CLexicalizedParser(Options op) {
		super(op);
	}

	public CLexicalizedParser(ParserData pd) {
		super(pd);
	}

	public CLexicalizedParser(String parserFileOrUrl, boolean isTextGrammar, Options op) {
		super(parserFileOrUrl, isTextGrammar, op);
	}

	public CLexicalizedParser(String treebankPath, FileFilter filt, Options op) {
		super(treebankPath, filt, op);
	}

	public CLexicalizedParser(String parserFileOrUrl, Options op, String... extraFlags) {
		super(parserFileOrUrl, op, extraFlags);
	}

	public CLexicalizedParser(String parserFileOrUrl, String... extraFlags) {
		super(parserFileOrUrl, extraFlags);
	}

	public CLexicalizedParser(String[] extraFlags) {
		super(extraFlags);
	}

	public CLexicalizedParser(Treebank trainTreebank, DiskTreebank secondaryTrainTreebank,
			double weight, GrammarCompactor compactor, Options op) {
		super(trainTreebank, secondaryTrainTreebank, weight, compactor, op);
	}

	public CLexicalizedParser(Treebank trainTreebank, GrammarCompactor compactor, Options op,
			Treebank tuneTreebank) {
		super(trainTreebank, compactor, op, tuneTreebank);
	}

	public CLexicalizedParser(Treebank trainTreebank, GrammarCompactor compactor, Options op) {
		super(trainTreebank, compactor, op);
	}

	public CLexicalizedParser(Treebank trainTreebank, Options op) {
		super(trainTreebank, op);
	}

	public Tree applyCCC(Object in) throws Exception {
		List<? extends HasWord> lst;
		if (in instanceof String) {
			TokenizerFactory<? extends HasWord> tf = op.tlpParams.treebankLanguagePack()
					.getTokenizerFactory();
			Tokenizer<? extends HasWord> tokenizer = tf.getTokenizer(new BufferedReader(
					new StringReader((String) in)));
			lst = tokenizer.tokenize();
		} else if (in instanceof List) {
			lst = (List<? extends HasWord>) in;
		} else {
			throw new IllegalArgumentException("Can only parse Sentence/List/String");
		}

		try {
			LexicalizedParserQuery pq = new LexicalizedParserQuery(this);
			if (pq.parse(lst)) {
				Tree bestparse = pq.getBestParse();
				// -10000 denotes unknown words
				bestparse.setScore(pq.getPCFGScore() % -10000.0);
				return bestparse;
			}
		} catch (Exception e) {
			System.err.println("Following exception caught during parsing:");
			e.printStackTrace();
			System.err
					.println("Recovering using fall through strategy: will construct an (X ...) tree.");
			throw e;
		}
		// if can't parse or exception, fall through
		// TODO: merge with ParserAnnotatorUtils
		TreeFactory lstf = new LabeledScoredTreeFactory();
		List<Tree> lst2 = new ArrayList<Tree>();
		for (HasWord obj : lst) {
			String s = obj.word();
			Tree t = lstf.newLeaf(s);
			Tree t2 = lstf.newTreeNode("X", Collections.singletonList(t));
			lst2.add(t2);
		}
		return lstf.newTreeNode("X", lst2);
	}

} // end class LexicalizedParser
